package main

import (
	"fmt"
	"io"
	"math"
	"reflect"
	"strconv"
)

type Unmarshaler interface {
	Unmarshal(dec *Decoder, info *ValueInfo)
}

type ValueInfo struct {
	name  string
	isBig bool
	bit   int
	info  string
}

func (i *ValueInfo) fromTag(tag reflect.StructTag) {
	name := tag.Get("name")
	if len(name) > 0 {
		i.name = name
	}

	sort := tag.Get("sort")
	if len(sort) > 0 {
		if sort == "big" {
			i.isBig = true
		} else if sort == "little" {
			i.isBig = false
		} else {
			panic("unsupported tag: `sort:\"" + sort + "\"`")
		}
	}

	bit := tag.Get("bit")
	if len(bit) > 0 {
		num, err := strconv.Atoi(bit)
		if (err != nil) || (num <= 0 || num > 64) {
			panic("unsupported tag: `bit:\"" + bit + "\"`")
		}
		i.bit = num
	}

	info := tag.Get("info")
	if len(info) > 0 {
		i.info = info
	}
}

type ItemAddFunc func(start, end int, name, info, value string)

func kindSize(kind reflect.Kind) int {
	size := 0
	switch kind {
	case reflect.Int, reflect.Uint:
		size = 32
	case reflect.Bool, reflect.Int8, reflect.Uint8:
		size = 8
	case reflect.Int16, reflect.Uint16:
		size = 16
	case reflect.Int32, reflect.Uint32, reflect.Float32:
		size = 32
	case reflect.Int64, reflect.Uint64, reflect.Uintptr, reflect.Float64, reflect.Complex64:
		size = 64
	case reflect.Complex128:
		size = 128
	default:
	}
	return size
}

type Decoder struct {
	buf      []byte
	prevOff  int
	off      int
	bit      int
	itemFunc ItemAddFunc
	arg      any
}

func NewDecoder(itemFunc ItemAddFunc, buf []byte, prevOff int) *Decoder {
	return &Decoder{buf: buf, prevOff: prevOff, itemFunc: itemFunc}
}

func (dec *Decoder) Pos() int {
	return (dec.prevOff+dec.off)*8 + dec.bit
}

func (dec *Decoder) Seek(pos int) {
	if pos < dec.prevOff*8 || pos > (dec.prevOff+len(dec.buf))*8 {
		panic(fmt.Sprintf("pos(%d.%d) illegal", pos/8, pos%8))
	}
	dec.off = pos/8 - dec.prevOff
	dec.bit = pos % 8
}

func (dec *Decoder) SubDecoder(n int) *Decoder {
	prevOff := dec.off
	if dec.bit > 0 {
		prevOff++
	}
	if n <= 0 || prevOff+n >= len(dec.buf) {
		n = len(dec.buf) - prevOff
	}
	return &Decoder{
		buf:      dec.buf[prevOff : prevOff+n],
		prevOff:  dec.prevOff + prevOff,
		itemFunc: dec.itemFunc,
		arg:      dec.arg,
	}
}

func (dec *Decoder) SetArg(a any) {
	dec.arg = a
}

func (dec *Decoder) Arg() any {
	return dec.arg
}

func (dec *Decoder) ItemAddFunc() ItemAddFunc {
	return dec.itemFunc
}

func (dec *Decoder) Read(p []byte) (n int, err error) {
	if dec.bit > 0 {
		dec.bit = 0
		dec.off++
	}
	if len(p) == 0 {
		return 0, nil
	}
	n = len(dec.buf) - dec.off
	if n <= 0 {
		return 0, io.EOF
	}
	if n > len(p) {
		n = len(p)
	}
	copy(p, dec.buf[dec.off:dec.off+n])
	dec.off += n
	return n, nil
}

func (dec *Decoder) ReadByte() (byte, error) {
	if dec.bit > 0 {
		dec.bit = 0
		dec.off++
	}
	if dec.off >= len(dec.buf) {
		return 0, io.EOF
	}
	b := dec.buf[dec.off]
	dec.off++
	return b, nil
}

func (dec *Decoder) ReadBytes(n int) []byte {
	if dec.bit > 0 {
		dec.bit = 0
		dec.off++
	}
	if dec.off >= len(dec.buf) {
		panic(io.EOF)
	}
	if n <= 0 || dec.off+n > len(dec.buf) {
		n = len(dec.buf) - dec.off
	}
	bs := dec.buf[dec.off : dec.off+n]
	dec.off += n
	return bs
}

func (dec *Decoder) IsEof() bool {
	if dec.bit > 0 {
		return false
	}
	return dec.off == len(dec.buf)
}

func (dec *Decoder) addItem(start int, v reflect.Value, info *ValueInfo) {
	if dec.itemFunc == nil {
		return
	}
	end := dec.Pos()
	if start >= end {
		return
	}

	if v.CanInterface() {
		if f, ok := v.Interface().(fmt.Stringer); ok {
			dec.itemFunc(start, end, info.name, info.info, f.String())
			return
		}
		if v.Kind() != reflect.Pointer {
			var a any
			if v.CanAddr() {
				a = v.Addr().Interface()
			} else {
				tmp := v.Interface()
				a = &tmp
			}
			if f, ok := a.(fmt.Stringer); ok {
				dec.itemFunc(start, end, info.name, info.info, f.String())
				return
			}
		}
	}

	if v.Kind() == reflect.Pointer {
		v = v.Elem()
	}

	val := ""
	switch v.Kind() {
	case reflect.Bool:
		if v.Bool() {
			val = "true"
		} else {
			val = "false"
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		val = fmt.Sprintf("0x%X(%d)", v.Int(), v.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		val = fmt.Sprintf("0x%X(%d)", v.Uint(), v.Uint())
	case reflect.Float32, reflect.Float64:
		val = strconv.FormatFloat(v.Float(), 'f', -1, kindSize(v.Kind()))
	case reflect.Complex64, reflect.Complex128:
		val = strconv.FormatComplex(v.Complex(), 'f', -1, kindSize(v.Kind()))
	case reflect.String:
		val = v.String()
	default:
	}
	dec.itemFunc(start, end, info.name, info.info, val)
}

func (dec *Decoder) Decode(a any, info *ValueInfo) {
	if a == nil {
		return
	}

	if info == nil {
		info = &ValueInfo{}
	}
	if v, ok := a.(reflect.Value); ok {
		dec.decode(v, info)
	}
	dec.decode(reflect.ValueOf(a), info)
}

func (dec *Decoder) decode(v reflect.Value, info *ValueInfo) {
	if !v.IsValid() {
		return
	}
	pos := dec.Pos()
	defer dec.addItem(pos, v, info)

	if v.CanInterface() {
		if f, ok := v.Interface().(Unmarshaler); ok {
			f.Unmarshal(dec, info)
			return
		}
	}
	if v.Kind() != reflect.Pointer && v.CanAddr() {
		if f, ok := v.Addr().Interface().(Unmarshaler); ok {
			f.Unmarshal(dec, info)
			return
		}
	}

	switch v.Kind() {
	case reflect.Bool:
		if v.CanSet() {
			v.SetBool(dec.decodeInteger(8, info) != 0)
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if v.CanSet() {
			v.SetInt(int64(dec.decodeInteger(kindSize(v.Kind()), info)))
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if v.CanSet() {
			v.SetUint(dec.decodeInteger(kindSize(v.Kind()), info))
		}
	case reflect.Float32, reflect.Float64:
		if v.CanSet() {
			v.SetFloat(dec.decodeFloat(kindSize(v.Kind()), info.isBig))
		}
	case reflect.Complex64, reflect.Complex128:
		if v.CanSet() {
			v.SetComplex(dec.decodeComplex(kindSize(v.Kind()), info.isBig))
		}
	case reflect.Slice:
		if v.IsNil() {
			dec.decodeSlice(v, info.isBig, info.bit)
			break
		}
		fallthrough
	case reflect.Array:
		l := v.Len()
		for i := 0; i < l; i++ {
			dec.decode(v.Index(i), &ValueInfo{name: strconv.Itoa(i), isBig: info.isBig, bit: info.bit})
		}
	case reflect.Interface, reflect.Pointer:
		if v.IsNil() {
			break
		}
		dec.decode(v.Elem(), info)
	case reflect.Map:
		dec.decodeMap(v, info.isBig, info.bit)
	case reflect.String:
		if v.CanSet() {
			v.SetString(dec.decodeString())
		}
	case reflect.Struct:
		dec.decodeStruct(v, info.isBig)
	default:
		return
	}
}

func (dec *Decoder) decodeInteger(size int, info *ValueInfo) uint64 {
	decFunc := dec.decodeLittleInteger
	if info.bit > 0 {
		size = info.bit
		if info.isBig {
			decFunc = dec.decodeBigBits
		} else {
			decFunc = dec.decodeLittleBits
		}
	} else if info.isBig {
		decFunc = dec.decodeBigInteger
	}
	return decFunc(size)
}

func (dec *Decoder) decodeLittleBits(size int) uint64 {
	v := uint64(0)
	bit := size
	for bit > 0 {
		if dec.off >= len(dec.buf) {
			panic(io.EOF)
		}
		num := 8 - dec.bit
		if num > bit {
			num = bit
		}

		mask := byte((1 << num) - 1)
		v |= uint64((dec.buf[dec.off]>>dec.bit)&mask) << (size - bit)
		dec.bit += num
		bit -= num

		if dec.bit >= 8 {
			dec.bit -= 8
			dec.off++
		}
	}
	return v
}

func (dec *Decoder) decodeBigBits(size int) uint64 {
	v := uint64(0)
	bit := size
	for bit > 0 {
		if dec.off >= len(dec.buf) {
			panic(io.EOF)
		}
		num := 8 - dec.bit
		if num > bit {
			num = bit
		}

		mask := byte((1 << num) - 1)
		v <<= num
		v |= uint64((dec.buf[dec.off] >> (8 - dec.bit - num)) & mask)
		dec.bit += num
		bit -= num

		if dec.bit >= 8 {
			dec.bit -= 8
			dec.off++
		}
	}
	return v
}

func (dec *Decoder) decodeLittleInteger(size int) uint64 {
	if size <= 0 || size%8 != 0 {
		panic(fmt.Sprintf("unsupport integer size: %d", size))
	}
	size /= 8
	bs := dec.ReadBytes(size)
	v := uint64(0)
	for i := 0; i < size; i++ {
		v |= uint64(bs[i]) << (i * 8)
	}
	return v
}

func (dec *Decoder) decodeBigInteger(size int) uint64 {
	if size <= 0 || size%8 != 0 {
		panic(fmt.Sprintf("unsupport integer size: %d", size))
	}
	size /= 8
	bs := dec.ReadBytes(size)
	v := uint64(0)
	for i := 0; i < size; i++ {
		v <<= 8
		v |= uint64(bs[i])
	}
	return v
}

func (dec *Decoder) decodeFloat(size int, isBig bool) float64 {
	decFunc := dec.decodeLittleInteger
	if isBig {
		decFunc = dec.decodeBigInteger
	}
	i := decFunc(size)

	switch size {
	case 32:
		return float64(math.Float32frombits(uint32(i)))
	case 64:
		return math.Float64frombits(i)
	default:
		panic(fmt.Sprintf("unsupport float size: %d", size))
	}
}

func (dec *Decoder) decodeComplex(size int, isBig bool) complex128 {
	r := dec.decodeFloat(size/2, isBig)
	i := dec.decodeFloat(size/2, isBig)
	return complex(r, i)
}

func (dec *Decoder) decodeString() string {
	if dec.bit > 0 {
		dec.bit = 0
		dec.off++
	}
	if dec.off >= len(dec.buf) {
		panic(io.EOF)
	}
	bs := dec.buf[dec.off:]
	n := 0
	for n < len(bs) && bs[n] != 0 {
		n++
	}
	dec.off += n
	if n < len(bs) {
		dec.off++
	}
	return string(bs[:n])
}

func (dec *Decoder) decodeSlice(v reflect.Value, isBig bool, bit int) {
	if !v.CanSet() {
		return
	}
	t := v.Type().Elem()
	if t.Kind() == reflect.Uint8 && bit == 0 {
		v.SetBytes(dec.ReadBytes(0))
		return
	}

	vt := v
	for i := 0; !dec.IsEof(); i++ {
		sv := reflect.New(t).Elem()
		dec.decode(sv, &ValueInfo{name: strconv.Itoa(i), isBig: isBig, bit: bit})
		vt = reflect.Append(vt, sv)
	}
	v.Set(vt)
}

func (dec *Decoder) decodeMap(v reflect.Value, isBig bool, bit int) {
	if !v.CanSet() {
		return
	}
	kt := v.Type().Key()
	vt := v.Type().Elem()
	switch kt.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
	case reflect.String:
	default:
		panic("unsupported key type of map: " + kt.String())
	}

	kvi := &ValueInfo{name: "key", isBig: isBig}
	vvi := &ValueInfo{name: "value", isBig: isBig, bit: bit}
	for !dec.IsEof() {
		pos := dec.Pos()
		kv := reflect.New(kt).Elem()
		vv := reflect.New(vt).Elem()
		dec.decode(kv, kvi)
		dec.decode(vv, vvi)
		v.SetMapIndex(kv, vv)
		dec.addItem(pos, vv, &ValueInfo{name: fmt.Sprint(kv)})
	}
}

func (dec *Decoder) decodeStruct(v reflect.Value, isBig bool) {
	t := v.Type()
	l := v.NumField()
	for i := 0; i < l; i++ {
		sv := v.Field(i)
		st := t.Field(i)
		if !st.IsExported() {
			continue
		}
		if !sv.CanSet() && st.Name == "_" {
			continue
		}

		info := &ValueInfo{name: st.Name, isBig: isBig}
		if st.Anonymous {
			info.name = st.Type.Name()
		}
		info.fromTag(st.Tag)

		dec.decode(sv, info)
	}
}
